<?php

require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'engine'.DIRECTORY_SEPARATOR.'init.php';
error_reporting(E_ALL);

sys::uses("tree");
sys::uses("sets/set");
header('Content-Type: text/plain; charset=UTF-8');

$sets = array(
    1 => new UnionSet(new SingleSet(str::getCode('+')), new SingleSet(45)),
    2 => new UnionSet(new SingleSet(str::getCode('+')), new SingleSet(0x2D)),
    3 => new SingleSet(str::getCode('x')),
    4 => new SingleSet(str::getCode('x')),
    5 => new SingleSet(str::getCode('^')),
    6 => new UnionSet(new RangeSet(str::getCode('0'), str::getCode('9'))),
);

$table = array(
    1 => array(
        "node" => "Polynom",
        "transitions" => array(
            array("optional" => true, "repeat" => false, "state" => null, "set" => 1, "literal" => null),
            array("optional" => false, "repeat" => false, "state" => 3, "set" => null, "literal" => null),
            array("optional" => true, "repeat" => true, "state" => 2, "set" => null, "literal" => null),
        )
    ),
    2 => array(
        "node" => null,
        "transitions" => array(
            array("optional" => false, "repeat" => false, "state" => null, "set" => 2, "literal" => null),
            array("optional" => false, "repeat" => false, "state" => 3, "set" => null, "literal" => null),
        )
    ),
    3 => array(
        "node" => "Addent",
        "transitions" => array(
            array("optional" => false, "repeat" => false, "state" => 6, "set" => null, "literal" => null),
            array("optional" => true, "repeat" => false, "state" => 4, "set" => null, "literal" => null),
            array("optional" => false, "repeat" => false, "state" => null, "set" => 4, "literal" => 'x'),
            array("optional" => true, "repeat" => false, "state" => 5, "set" => null, "literal" => null),
        )
    ),
    4 => array(
        "node" => null,
        "transitions" => array(
            array("optional" => false, "repeat" => false, "state" => null, "set" => 3, "literal" => 'x'),
            array("optional" => true, "repeat" => false, "state" => 5, "set" => null, "literal" => null),
        )
    ),
    5 => array(
        "node" => "Power",
        "transitions" => array(
            array("optional" => false, "repeat" => false, "state" => null, "set" => 5, "literal" => '^'),
            array("optional" => false, "repeat" => false, "state" => 6, "set" => null, "literal" => null),
        )
    ),
    6 => array(
        "node" => "Number",
        "transitions" => array(
            array("optional" => false, "repeat" => true, "state" => null, "set" => 6, "literal" => null),
        )
    ),
);

class Automata
{
    private $sets = array();
    private $table = array();
    private $state = array();
    private $char = null;

    /**
     * @var Tree
     */
    public $tree = null;
    private $stack_to_tree = array();

    function __construct($sets, $table)
    {
        $this->sets = $sets;
        $this->table = $table;
        $this->tree =& new Tree();
    }

    function propcess($string)
    {
        $this->parser = new Parser($string);
        $stack = array(array(1 => 0));
        if (isset($this->table[1]["node"])) {
            $this->parser->createChild($this->table[1]["node"]);
        }
        for ($i = 0; $i < strlen($string); $i++) {
            $iterator = end($stack);
            $iterator = reset($stack);
            $state = key($stack);
            $rows = count($this->table[$state]["transitions"]);
            $transition = $this->table[$state]["transitions"][$iterator];

            if ($transition["optional"]) {
                if ($transition["repeat"]) {

                } else {

                }
            } else {
                if ($transition["repeat"]) {

                } else {

                }
            }
            /*do {
                $this->table[$state]
            } while ($iterator < $rows);*/
        }
        $this->parser->endChild();

        return $this->parser->getTree()->saveXML();
    }

    private function checkCharForStateAndTransition($state, $transition, &$stack)
    {
        $iterator = $transition;
        $transitions = count($this->table[$state]["transitions"]);
        do {
            $transition = $this->table[$state]["transitions"][$iterator];
            $result = false;
            if (isset($transition["set"])) {
                $result = $this->checkChar($transition["set"]);
            } else {
                $result = $this->checkCharForState($transition["state"], $stack);
            }
            if ($result) {
                if (isset($transition["set"])) {
                    $stack[ar::length($stack) - 1] = array(key(end($stack)) => $iterator);
                } else {
                    $stack = ar::concat($stack, $tmp_stack);
                }
                return true;
            }
            $iterator++;
        } while (($iterator < $transitions) && $transition["optional"]);

        return false;
    }

    private function intoState($state, $transition)
    {
        if (isset($this->table[$state]["node"])) {
            $this->createChild($this->table[$state]["node"]);
        }
        array_push($this->state, array($state, $transition));
    }

    private function outState()
    {
        $state = array_pop($this->state);
        if (isset($this->table[key($state)]["node"])) {
            $this->endChild();
        }
    }

    private function parse($chr)
    {
        $chr = new SingleSet($chr);
        $this->char = $chr->element();
    }

    private function checkCharForState($state)
    {
        $stack = array();
        if ($this->checkCharForStateRecursive($state, $stack)) {
            foreach ($stack as $_state => $_transition) {
                $this->intoState($_state, $_transition);
            }
        }
    }

    private function checkCharForStateRecursive($state, &$stack)
    {
        foreach ($this->table[$state]["transitions"] as $transition) {
            if ($transition["optional"]) {
                if ($transition["repeat"]) {
                    if (isset($transition["set"])) {
                        $result = $this->checkChar($transition["set"]);
                        $this->{__FUNCTION__}($state, $stack);
                    }
                } else {

                }
            } else {
                if ($transition["repeat"]) {

                } else {

                }
            }
        }
        return false;
    }

    private function checkChar($set_index)
    {
        return $this->sets[$set_index]->has_a($this->char);
    }

    private function getTree()
    {
        return $this->tree->getDOM();
    }

    private function addChar()
    {
        array_push($this->stack_to_tree, str::getChar($this->char));
    }

    private function createChild($name)
    {
        $this->flushStackToTree();
        $this->tree->createChild($name);
    }

    private function endChild()
    {
        $this->flushStackToTree();
        $this->tree->endChild();
    }

    private function flushStackToTree()
    {
        if (count($this->stack_to_tree)) {
            $text = '';
            foreach ($this->stack_to_tree as $chr) {
                $text .= $chr;
            }
            $this->tree->write($text);
            $this->stack_to_tree = array ();
        }
    }
}

$automata = new Automata($sets, $table);
$xml = $automata->propcess('-123x^4 + 567x + 89');

header('Content-Type: text/xml; charset=UTF-8');
echo $xml;

?>